<?php


namespace App\Services;


use App\Services\Java\ApiService;
use Carbon\Carbon;
use D1M\Common\Exceptions\AuthFailedException;
use D1M\Common\Exceptions\BusinessException;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class Login extends Base
{
    public function login($users)
    {

//            "data" => array:3 [
//    "manageNo" => "1673174699458215937"
//    "loginName" => "test"
//    "shopCode" => "456"
//  ]

//        ];
//        if($res['code'] !=0) throw new BusinessException($res['message']);
        //自定义token存储在redis
        return $this->selfToken($users);

        //方案一  jwt
        //return $this->generatorToken($res['data']);
    }

    /**
     * 生成token
     */
    public function generatorToken($data)
    {
        $key = env("JWT_KEY");  //这里是自定义的一个随机字串，应该写在config文件中的，解密时也会用，相当    于加密中常用的 盐  salt
        $token = [
            //"iss"=>"",  //签发者 可以为空
            //"aud"=>"", //面象的用户，可以为空
            "iat" => time(), //签发时间
            "nbf" => time(), //在什么时候jwt开始生效  (这里表示生成100秒后才生效)
            "exp" => time()+env("JWT_EXPIRE_TIME"), //token 过期时间 秒 自定义
            "uid" => $data['id'] //记录的userid的信息，这里是自已添加上去的，如果有其它信息，可以再添加数组的键值对
        ];
        $jwt = JWT::encode($token,$key); //根据参数生成了 token  "HS256"

        $token['exp'] = time()+env("JWT_REFRESH_EXPIRE_TIME");
        $refreshToken = JWT::encode($token,$key);
        //dump($jwt);
        //dump($refreshToken);
        //记录到redis中
        $redisKey = 'pos:jwt_login:token:'.$data['id'];
        $refreshKey = 'pos:jwt_login:refresh_token:'.$data['id'];
        Redis::del($redisKey);
        Redis::del($refreshKey);
        Redis::set($redisKey,$jwt);
        Redis::expire($redisKey,7200);
        Redis::set($refreshKey,$refreshToken);
        Redis::expire($refreshKey,86400);

        return [
            'token'=>$jwt,
            'token_type'=>'Bearer',
            'refresh_token'=>$refreshToken
        ];

    }

    public function checkToken($request,$type=0)
    {
        if (!$request->hasHeader('Authorization')) {
            throw new AuthFailedException('您尚未登录或登录已过期，请重新登录~',-1002);
        }

        $authorization = $request->header('Authorization');
        $token = str_replace('Bearer ', '', $authorization);
        $key = env("JWT_KEY");
        try{
            $info = JWT::decode($token,$key,["HS256"]); //解密jwt
            //确认redis中是否存在此key
            $redisKey = 'pos:jwt_login:token:'.$info->uid;
            if($type){
                $redisKey = 'pos:jwt_login:refresh_token:'.$info->uid;
            }
            $redis = Redis::get($redisKey);
            if(!$redis || $redis !=$token){
                throw new AuthFailedException('token失效',-1002);
            }
        }catch (SignatureInvalidException $e) { //签名不正确
            throw new AuthFailedException('签名不正确～',-1002);
        } catch (BeforeValidException $e) { // 签名在某个时间点之后才能用
            throw new AuthFailedException('账号未到可用时间～',-1002);
        } catch (ExpiredException $e) { // token过期
            throw new AuthFailedException('token失效～',-1002);
        } catch (\Exception $e) { //其他错误
            throw new AuthFailedException($e->getMessage(),-1002);
        }

        //dump($info);
        return $info;

    }


    public function refershToken($request)
    {
        $info = $this->checkToken($request,1);
        $data = [
            'id'=>$info->uid
        ];
        return $this->generatorToken($data);
    }


    public function me($request)
    {
        //通过ID获取用户信息  或者封装到token中 或者存储在redis中
        //PHP设计不允许多点登录   token失效
        return $this->selfCheckToken($request);
    }


    /**
     * 自定义token 存储redis
     */
    public function selfToken($data)
    {
        //$data['id'] = 1;
        $tokenData = [
            'manage_no'=>$data['manageNo'],
            'login_name'=>$data['loginName'],
            'shop_code'=>$data['shopCode'],
            'shop_id'=>$data['shopId'],
            'shop_name'=>$data['shopName'],
            'real_name'=>$data['realName'],
            'role_names'=>$data['roleNames'],
            'generation_time'=>time()
        ];
        $token = $this->encrypt(json_encode($tokenData));
        //dump($token);

        //记录到redis中
        $redisKey = 'pos:self_login:token:'.$data['manageNo'];
        //Redis::del($redisKey);
        Redis::set($redisKey,$token);
        Redis::expire($redisKey,env("USER_LOGIN_EXPIRE_TIME"));

        return [
            'token'=>$token,
            'token_type'=>'Bearer',
            'expire_time'=>time()+env("USER_LOGIN_EXPIRE_TIME")
            //'refresh_token'=>$refreshToken
        ];

    }

    /**
     * 获取用户ID
     * @param $request
     * @return mixed
     */
    public function selfCheckToken($request)
    {
        $token = $request->header('Authorization');
        $token = str_replace('Bearer ', '', $token);
        Log::info('个人信息token:'.$token);
        $data = json_decode($this->decrypt($token));
        if(!$data){
            throw new BusinessException('验证信息无效～');
        }
        Log::info('个人信息data->manage_no:'.$data->manage_no);
        $redisKey = 'pos:self_login:token:'.$data->manage_no;
        $redis = Redis::get($redisKey);
        Log::info('个人信息redis:'.$redis);
        if(!$redis || $redis !=$token){
            throw new BusinessException('登录失效请重新登录～',-2);
        }
        return $data;
    }

    public function logout($request)
    {
        $data = $this->selfCheckToken($request);
        $redisKey = 'pos:self_login:token:'.$data->manage_no;
        Redis::del($redisKey);
        return '退出登录';
    }




}